package com.zzb.mail;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Properties;
import java.util.regex.Pattern;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Authenticator;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;

import com.zzb.util.ReadPropertiesUtil;
import com.zzb.util.StringUtil;

public class EmailSendUtil {
	private ReadPropertiesUtil rdp = new ReadPropertiesUtil("email.properties");
	private ReadPropertiesUtil rddp = new ReadPropertiesUtil(
			"defaultEmailServer.properties");
	private String userName;
	private String password;
	private String mailServerHost;
	private String mailServerPort;
	private boolean isSSL;

	public String getUserName() {
		return userName;
	}

	public String getPassword() {
		return password;
	}

	public String getMailServerHost() {
		return mailServerHost;
	}

	public String getMailServerPort() {
		return mailServerPort;
	}

	public Session getSendMailSession() {
		return sendMailSession;
	}

	private Session sendMailSession;

	public EmailSendUtil(String userName, String password,
			String mailServerHost, String mailServerPort,boolean isSSL) throws Exception {
		if(StringUtil.isEmpty(userName)){
			this.userName = rdp.getProperties("username");
		}else{
			this.userName = userName;
		}
		if(StringUtil.isEmpty(password)){
			this.password = rdp.getProperties("password");
		}else{
			this.password = password;
		}
		
		this.mailServerHost = getMailSendServer(mailServerHost, userName);
		this.isSSL = isSSL;
		this.mailServerPort = getMailSendPort(mailServerPort,userName,isSSL);
		if(this.mailServerPort == null){
			throw new Exception("无法创建邮件发送器");
		}
		// 创建一个密码验证器
		EmailUser emailUser = new EmailUser(this.userName, this.password);
		Properties pro = getProperties(this.mailServerHost, this.mailServerPort,this.isSSL);
		// 根据邮件会话属性和密码验证器构造一个发送邮件的session
		sendMailSession = Session.getDefaultInstance(pro, emailUser);
	}

	public EmailSendUtil(EmailSendInfo emailSendInfo) throws Exception {
		this(emailSendInfo.getUserName(), emailSendInfo.getPassword(),
				emailSendInfo.getMailServerHost(), emailSendInfo
						.getMailServerPort(),emailSendInfo.isSSL());
	}

	/**
	 * @param sendTo
	 *            发送给，以","分割的多个邮件地址
	 * @param sendCC
	 *            抄送给，以","分割的多个邮件地址
	 * @param sendBCC
	 *            密送给，以","分割的多个邮件地址
	 * @param subject
	 *            主题
	 * @param content
	 *            内容
	 * @param contentCharSet
	 *            内容编码，仅供内容为html时使用，值喂utf-8、gbk等
	 * @param attachments
	 *            文件
	 * @param is_url
	 *            内容编码，仅供内容为html时使用，值喂utf-8、gbk等
	 * @return 1:发送成功，2：地址错误，3：消息错误，4：收件人未填
	 */
	public int send(String sendTo, String sendCC, String sendBCC,
			String subject, String content, String contentCharSet,
			String attachments, boolean is_url) {
		try {
			Address[] addresses = getAddresses(sendTo);
			if (addresses == null)
				return 4;
			// 根据session创建一个邮件消息
			Message mailMessage = new MimeMessage(sendMailSession);
			// 创建邮件发送者地址
			Address from = new InternetAddress(userName);
			// 设置邮件消息的发送者
			mailMessage.setFrom(from);
			// 创建邮件的接收者地址，并设置到邮件消息中
			mailMessage.setRecipients(Message.RecipientType.TO, addresses);
			addresses = getAddresses(sendCC);
			if (addresses != null && addresses.length > 0) {
				mailMessage.setRecipients(Message.RecipientType.CC, addresses);
			}
			addresses = getAddresses(sendBCC);
			if (addresses != null && addresses.length > 0) {
				mailMessage.setRecipients(Message.RecipientType.BCC, addresses);
			}
			// 设置邮件消息的主题
			mailMessage.setSubject(StringUtil
					.getNotNullString(subject, "（无主题）"));
			// 设置邮件消息发送的时间
			mailMessage.setSentDate(new Date());
			// MiniMultipart类是一个容器类，包含MimeBodyPart类型的对象
			Multipart mainPart = new MimeMultipart();
			// 创建一个包含HTML内容的MimeBodyPart
			BodyPart bodyPart = new MimeBodyPart();
			if (!StringUtil.isEmpty(contentCharSet)) {
				// 设置HTML内容
				bodyPart.setContent(content, "text/html; charset="
						+ contentCharSet);
			} else {
				// 设置邮件消息的主要内容
				bodyPart.setText(content);
			}
			mainPart.addBodyPart(bodyPart);
			if (!StringUtil.isEmpty(attachments)) {
				String[] tmp = attachments.split(",");
				for (String string : tmp) {
					MimeBodyPart pf2 = getAttachment(string, is_url);
					if (pf2 != null) {
						mainPart.addBodyPart(pf2);
					}
				}
			}
			// 将MiniMultipart对象设置为邮件内容
			mailMessage.setContent(mainPart);
			// 发送邮件
			Transport.send(mailMessage);
		} catch (AddressException e) {
			e.printStackTrace();
			return 2;
		} catch (MessagingException e) {
			e.printStackTrace();
			return 3;
		}
		return 1;
	}

	private MimeBodyPart getAttachment(String attachment, boolean is_url) {
		MimeBodyPart pf2 = new MimeBodyPart();
		try {
			if (is_url) {
				try {
					URL url = new URL(attachment);
					pf2.setDataHandler(new DataHandler(url));
				} catch (MalformedURLException e) {
					e.printStackTrace();
				}
			} else {
				File save_file = new File(attachment);
				if (!save_file.exists())
					return null;
				if (!save_file.canRead())
					return null;
				pf2.setDataHandler(new DataHandler(new FileDataSource(save_file)));
			}
			pf2.setFileName(MimeUtility.encodeText(attachment.substring(attachment
					.lastIndexOf("\\"))));
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
		return pf2;
	}
	/**
	 * 
	 * @param message 要回复的邮件对象
	 * @param replayAll 是否回复全部，true-全部，false-回复发送者
	 * @param subject 主题，默认将“Re：”作为邮件的主题
	 * @param content 正文内容
	 * @param contentCharSet 编码，html格式需要填写
	 * @param attachments 附件路径，多个以“,”分割
	 * @param is_url 附件路径类型是url还是文件路径，true-url，false-文件路径
	 * @return
	 */
	public void reply(Message message,boolean replayAll,String subject, String content, String contentCharSet,
			String attachments, boolean is_url) {
		try {
			MimeMessage reply = (MimeMessage) message.reply(replayAll);
			reply.setFrom(new InternetAddress(userName));
			if(!StringUtil.isEmpty(subject)){
				reply.setSubject(subject);
			}
			// MiniMultipart类是一个容器类，包含MimeBodyPart类型的对象
			Multipart mainPart = new MimeMultipart();
			// 创建一个包含HTML内容的MimeBodyPart
			BodyPart bodyPart = new MimeBodyPart();
			if (!StringUtil.isEmpty(contentCharSet)) {
				// 设置HTML内容
				bodyPart.setContent(content, "text/html; charset="
						+ contentCharSet);
			} else {
				// 设置邮件消息的主要内容
				bodyPart.setText(content);
			}
			mainPart.addBodyPart(bodyPart);
			if (!StringUtil.isEmpty(attachments)) {
				String[] tmp = attachments.split(",");
				for (String string : tmp) {
					MimeBodyPart pf2 = getAttachment(string, is_url);
					if (pf2 != null) {
						mainPart.addBodyPart(pf2);
					}
				}
			}
			reply.setContent(mainPart);
			Transport.send(reply);
		} catch (AddressException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 发送文本或html格式邮件
	 * 
	 * @param sendTo
	 *            发送给，以","分割的多个邮件地址
	 * @param sendCC
	 *            抄送给，以","分割的多个邮件地址
	 * @param sendBCC
	 *            密送给，以","分割的多个邮件地址
	 * @param subject
	 *            主题
	 * @param content
	 *            内容
	 * @param contentCharSet
	 *            内容编码，仅供内容为html时使用，值喂utf-8、gbk等
	 * @return 1:发送成功，2：地址错误，3：消息错误，4：收件人未填
	 */
	public int send(String sendTo, String sendCC, String sendBCC,
			String subject, String content, String contentCharSet) {
		return send(sendTo, sendCC, sendBCC, subject, content, contentCharSet,
				"", false);
	}

	public int send(String sendTo, String sendCC, String sendBCC,
			String subject, String content, String attachments, boolean is_url) {
		return send(sendTo, sendCC, sendBCC, subject, content, "", attachments,
				is_url);
	}

	/**
	 * 发送文本格式简单邮件
	 * 
	 * @param sendTo
	 *            发送给，以","分割的多个邮件地址
	 * @param sendCC
	 *            抄送给，以","分割的多个邮件地址
	 * @param sendBCC
	 *            密送给，以","分割的多个邮件地址
	 * @param subject
	 *            主题
	 * @param content
	 *            内容
	 * @return 1:发送成功，2：地址错误，3：消息错误，4：收件人未填
	 */
	public int send(String sendTo, String sendCC, String sendBCC,
			String subject, String content) {
		return send(sendTo, sendCC, sendBCC, subject, content, "");
	}

	/**
	 * 
	 * @param sendTo
	 * @param subject
	 * @param content
	 * @return
	 */
	public int send(String sendTo, String subject, String content) {
		return send(sendTo, "", "", subject, content);
	}

	/**
	 * 
	 * @param sendTo
	 * @param subject
	 * @param content
	 * @param contentCharSet
	 * @return
	 */
	public int send(String sendTo, String subject, String content,
			String contentCharSet) {
		return send(sendTo, "", "", subject, content, contentCharSet);
	}

	public int send(TextEmailMessage message) {
		return send(message.getSendTo(), message.getSendCC(),
				message.getSendBCC(), message.getSubject(),
				message.getContent(), message.getAttachments(),
				message.isIs_url());
	}

	public int send(HtmlEmailMessage message) {
		return send(message.getSendTo(), message.getSendCC(),
				message.getSendBCC(), message.getSubject(),
				message.getContent(), message.getContentCharSet(),
				message.getAttachments(), message.isIs_url());
	}

	/**
	 * 检查email地址是否符合格式
	 * 
	 * @param email
	 * @return
	 */
	private boolean checkEmail(String email) {
		if (!StringUtil.isEmpty(email)) {
			String check = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$";
			return Pattern.compile(check).matcher(email).matches();
		} else {
			return false;
		}
	}

	private Address[] getAddresses(String emailList) throws AddressException {
		if (StringUtil.isEmpty(emailList))
			return null;
		String[] emails = emailList.split(",");
		HashMap<String, String> map = new HashMap<String, String>();
		for (String email : emails) {
			if (checkEmail(email))
				map.put(email, null);
		}
		if (map.size() > 0) {
			StringBuilder str = new StringBuilder();
			for (String email : map.keySet()) {
				str.append(email).append(",");
			}
			return InternetAddress.parse(str.toString(), true);
		} else {
			return null;
		}
	}

	public void close() {

	}

	private String getMailSendServer(String mailSendServer, String userName) {
		if (StringUtil.isEmpty(mailSendServer)) {
			String server = userName.substring(userName.indexOf("@") + 1);
			String defaultServer = rddp.getProperties(server + ".smtp");
			if (StringUtil.isEmpty(defaultServer)) {
				return "smtp." + server;
			} else {
				return defaultServer;
			}
		} else {
			return mailSendServer;
		}
	}
	private String getMailSendPort(String mailSendPort, String userName,boolean isSSL) {
		if (StringUtil.isEmpty(mailSendPort)) {
			String server = userName.substring(userName.indexOf("@") + 1)+".smtp.port";
			if(isSSL){
				String defaultPort = rddp.getProperties("ssl." + server);
				if (StringUtil.isEmpty(defaultPort)) {
					return "587";
				} else {
					return defaultPort;
				}
			}else{
				String defaultPort = rddp.getProperties(server);
				if (StringUtil.isEmpty(defaultPort)) {
					return "25";
				} else {
					return defaultPort;
				}
			}
		} else {
			return mailSendPort;
		}
	}

	/**
	 * 获得邮件会话属性
	 */
	private Properties getProperties(String mailServerHost,
			String mailServerPort,boolean isSSL) {
		if (!StringUtil.isEmpty(mailServerHost)
				&& !StringUtil.isEmpty(mailServerPort)) {
			if(isSSL){
//				Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

				final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
				// Get a Properties object
				Properties props = System.getProperties();
				props.setProperty("mail.smtp.host", mailServerHost);
				props.setProperty("mail.smtp.port", mailServerPort);
				props.put("mail.smtp.auth", "true");
				props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
				props.setProperty("mail.smtp.socketFactory.fallback", "false");
				props.setProperty("mail.smtp.socketFactory.port", mailServerPort);
				return props;
			}else{
				Properties p = new Properties();
				p.put("mail.smtp.host", mailServerHost);
				p.put("mail.smtp.port", mailServerPort);
				p.put("mail.smtp.auth", "true");
				return p;
			}
		} else {
			return null;
		}
	}
	public static void main(String[] args) {
		try {
			EmailSendInfo emailSendInfo = new EmailSendInfo("zb.zhang@morningwhistle.com", "54a12326");
			EmailSendUtil emailSendUtil = new EmailSendUtil(emailSendInfo);
			TextEmailMessage message = new TextEmailMessage("", "", "测试2");
			message.setSendBCC("864141317@qq.com,zb.zhang@morningwhistle.com,lixin@chinamerger.com");
			emailSendUtil.send(message);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public boolean isSSL() {
		return isSSL;
	}

	public void setSSL(boolean isSSL) {
		this.isSSL = isSSL;
	}

	private class EmailUser extends Authenticator {
		String userName = null;
		String password = null;

		public EmailUser(String username, String password) {
			this.userName = username;
			this.password = password;
		}

		@Override
		protected PasswordAuthentication getPasswordAuthentication() {
			return new PasswordAuthentication(userName, password);
		}
	}
}
